/*
REWRITTEN BY XINEF
*/

#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "sunwell_plateau.h"
#include "MoveSplineInit.h"
#include "CreatureTextMgr.h"

enum Yells
{
    SAY_KJ_OFFCOMBAT                            = 0,

    SAY_KALECGOS_ENCOURAGE                      = 0,
    SAY_KALECGOS_READY1                         = 1,
    SAY_KALECGOS_READY2                         = 2,
    SAY_KALECGOS_READY_ALL                      = 3,
    SAY_KALECGOS_AWAKEN                         = 5,
    SAY_KALECGOS_LETGO                          = 6,
    SAY_KALECGOS_FOCUS                          = 7,
    SAY_KALECGOS_FATE                           = 8,
    SAY_KALECGOS_GOODBYE                        = 9,
    SAY_KALECGOS_JOIN                           = 10,

    SAY_KJ_DEATH                                = 0,
    SAY_KJ_SLAY                                 = 1,
    SAY_KJ_REFLECTION                           = 2,
    SAY_KJ_EMERGE                               = 3,
    SAY_KJ_DARKNESS                             = 4,
    SAY_KJ_PHASE3                               = 5,
    SAY_KJ_PHASE4                               = 6,
    SAY_KJ_PHASE5                               = 7,
    EMOTE_KJ_DARKNESS                           = 8,

    SAY_ANVEENA_IMPRISONED                      = 0,
    SAY_ANVEENA_LOST                            = 1,
    SAY_ANVEENA_KALEC                           = 2,
    SAY_ANVEENA_GOODBYE                         = 3
};

enum Spells
{
	// Kil'jaeden spells
	SPELL_REBIRTH								= 44200,
	SPELL_SOUL_FLAY								= 45442,
	SPELL_LEGION_LIGHTNING						= 45664,
	SPELL_FIRE_BLOOM							= 45641,
	SPELL_SHADOW_SPIKE							= 46680,
	SPELL_SINISTER_REFLECTION					= 45892,
	SPELL_FLAME_DART							= 45737,
	SPELL_FLAME_DART_EXPLOSION					= 45746,
	SPELL_DARKNESS_OF_A_THOUSAND_SOULS			= 46605,
	SPELL_DARKNESS_OF_A_THOUSAND_SOULS_DAMAGE	= 45657,
	SPELL_ARMAGEDDON_PERIODIC					= 45921,
	SPELL_ARMAGEDDON_VISUAL						= 45911,
	SPELL_ARMAGEDDON_MISSILE					= 45909,
	SPELL_CUSTOM_08_STATE						= 45800,
	SPELL_DESTROY_ALL_DRAKES					= 46707,

	// Sinister Reflections
	SPELL_SINISTER_REFLECTION_SUMMON			= 45891,
	SPELL_SINISTER_REFLECTION_CLASS				= 45893,
	SPELL_SINISTER_REFLECTION_CLONE				= 45785,

	// Misc
	SPELL_ANVEENA_ENERGY_DRAIN					= 46410,
	SPELL_RING_OF_BLUE_FLAMES					= 45825,
	SPELL_SUMMON_BLUE_DRAKE						= 45836,
	SPELL_VENGEANCE_OF_THE_BLUE_FLIGHT			= 45839,
	SPELL_POSSESS_DRAKE_IMMUNITY				= 45838,
	SPELL_SACRIFICE_OF_ANVEENA					= 46474,
};

enum Misc
{
	PHASE_DECEIVERS					= 1,
	PHASE_NORMAL					= 2,
	PHASE_DARKNESS					= 3,
	PHASE_ARMAGEDDON				= 4,
	PHASE_SACRIFICE					= 5,

	EVENT_GROUP_SPEACH				= 1,
	ACTION_START_POST_EVENT			= 1,
	ACTION_NO_KILL_TALK				= 2,

	// Text events
	EVENT_TEXT_SPEACH11				= 1,
	EVENT_TEXT_SPEACH21				= 2,
	EVENT_TEXT_SPEACH22				= 3,
	EVENT_TEXT_SPEACH23				= 4,
	EVENT_TEXT_SPEACH31				= 5,
	EVENT_TEXT_SPEACH32				= 6,
	EVENT_TEXT_SPEACH33				= 7,
	EVENT_TEXT_SPEACH41				= 8,
	EVENT_TEXT_SPEACH42				= 9,
	EVENT_TEXT_SPEACH43				= 10,
	EVENT_TEXT_SPEACH44				= 11,
	EVENT_TEXT_SPEACH45				= 12,
	EVENT_TEXT_SPEACH46				= 13,

	// Controller events
	EVENT_RANDOM_TALK				= 40,
	EVENT_CHECK_PLAYERS				= 41,

	// Misc fight events
	EVENT_REBIRTH					= 50,
	EVENT_INIT_FIGHT				= 51,
	EVENT_CHECK_HEALTH85			= 52,
	EVENT_CHECK_HEALTH55			= 53,
	EVENT_CHECK_HEALTH25			= 54,
	EVENT_EMPOWER_ORBS1				= 55,
	EVENT_EMPOWER_ORBS2				= 56,
	EVENT_EMPOWER_ORBS3				= 57,
	EVENT_RESTORE_MELEE				= 58,
	EVENT_KILL_SELF					= 59,
	EVENT_NO_KILL_TALK				= 60,

	// Abilities events
	EVENT_SPELL_SOUL_FLAY			= 100,
	EVENT_SPELL_LEGION_LIGHTNING	= 101,
	EVENT_SPELL_FIRE_BLOOM			= 102,
	EVENT_SUMMON_ORBS				= 103,
	EVENT_SPELL_SHADOW_SPIKE		= 104,
	EVENT_SPELL_SINISTER_REFLECTION	= 105,
	EVENT_SPELL_FLAME_DART			= 106,
	EVENT_SPELL_DARKNESS			= 107,
	EVENT_SPELL_ARMAGEDDON			= 108,
};

class CastArmageddon : public BasicEvent
{
    public:
        CastArmageddon(Creature* caster) : _caster(caster)
        {
        }

        bool Execute(uint64 /*execTime*/, uint32 /*diff*/)
        {
			_caster->CastSpell(_caster, SPELL_ARMAGEDDON_MISSILE, true);
			_caster->SetPosition(_caster->GetPositionX(), _caster->GetPositionY(), _caster->GetPositionZ()-20.0f, 0.0f);
            return true;
        }

    private:
        Creature* _caster;
};

class npc_kiljaeden_controller : public CreatureScript
{
public:
    npc_kiljaeden_controller() : CreatureScript("npc_kiljaeden_controller") { }

    CreatureAI* GetAI(Creature* creature) const
    {
        return GetInstanceAI<npc_kiljaeden_controllerAI>(creature);
    }

    struct npc_kiljaeden_controllerAI : public NullCreatureAI
    {
        npc_kiljaeden_controllerAI(Creature* creature) : NullCreatureAI(creature), summons(me)
        {
            instance = creature->GetInstanceScript();
        }

		EventMap events;
        InstanceScript* instance;
        SummonList summons;

		void ResetOrbs()
		{
			for (uint8 i = 0; i < 4; ++i)
				if (GameObject* orb = ObjectAccessor::GetGameObject(*me, instance->GetData64(DATA_ORB_OF_THE_BLUE_DRAGONFLIGHT_1+i)))
					orb->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE);
		}

        void Reset()
        {
			instance->SetBossState(DATA_KILJAEDEN, NOT_STARTED);
			events.Reset();
			summons.DespawnAll();
			ResetOrbs();

			me->SummonCreature(NPC_HAND_OF_THE_DECEIVER, 1702.62f, 611.19f, 27.66f, 1.81f, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 30000);
			me->SummonCreature(NPC_HAND_OF_THE_DECEIVER, 1684.099f, 618.848f, 27.67f, 0.589f, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 30000);
			me->SummonCreature(NPC_HAND_OF_THE_DECEIVER, 1688.38f, 641.10f, 27.50f, 5.43f, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 30000);
			me->SummonCreature(NPC_ANVEENA, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ()+40.0f, 0.0f);

			me->CastSpell(me, SPELL_DESTROY_ALL_DRAKES, true);
			me->CastSpell(me, SPELL_ANVEENA_ENERGY_DRAIN, true);
			events.ScheduleEvent(EVENT_RANDOM_TALK, 60000);
        }

		void JustDied(Unit*)
		{
			EntryCheckPredicate kilCheck(NPC_KILJAEDEN);
			EntryCheckPredicate kalCheck(NPC_KALECGOS_KJ);
			summons.DespawnIf(kilCheck);
			summons.DoAction(ACTION_START_POST_EVENT, kalCheck);
			summons.DespawnIf(kalCheck);

			me->CastSpell(me, SPELL_DESTROY_ALL_DRAKES, true);
			summons.DespawnAll();
		}

        void JustSummoned(Creature* summon)
        {
            summons.Summon(summon);
			if (summon->GetEntry() == NPC_SINISTER_REFLECTION)
				summon->SetInCombatWithZone();
			else if (summon->GetEntry() == NPC_KALECGOS_KJ)
				summon->setActive(true);
        }

		void SummonedCreatureDies(Creature* summon, Unit*)
		{
			summons.Despawn(summon);

			if (summon->GetEntry() == NPC_HAND_OF_THE_DECEIVER)
			{
				instance->SetBossState(DATA_KILJAEDEN, IN_PROGRESS);
				events.ScheduleEvent(EVENT_CHECK_PLAYERS, 1000);

				if (!summons.HasEntry(NPC_HAND_OF_THE_DECEIVER))
				{
					me->RemoveAurasDueToSpell(SPELL_ANVEENA_ENERGY_DRAIN);
					me->SummonCreature(NPC_KILJAEDEN, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ()+1.5f, 4.3f, TEMPSUMMON_MANUAL_DESPAWN);
					me->SummonCreature(NPC_KALECGOS_KJ, 1726.80f, 661.43f, 138.65f, 3.95f, TEMPSUMMON_MANUAL_DESPAWN);
				}
			}
		}

        void UpdateAI(uint32 diff)
        {
			events.Update(diff);
			switch (events.ExecuteEvent())
			{
				case EVENT_RANDOM_TALK:
					if (instance->GetBossState(DATA_KILJAEDEN) == NOT_STARTED)
						Talk(SAY_KJ_OFFCOMBAT);
					events.ScheduleEvent(EVENT_RANDOM_TALK, urand(90000, 180000));
					break;
				case EVENT_CHECK_PLAYERS:
				{
					Map::PlayerList const& players = me->GetMap()->GetPlayers();
					for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr)
						if (Player* player = itr->GetSource())
							if (!player->IsGameMaster() && me->GetDistance2d(player) < 60.0f && player->IsAlive())
							{
								events.ScheduleEvent(EVENT_CHECK_PLAYERS, 1000);
								return;
							}

					CreatureAI::EnterEvadeMode();
					break;
				}
			}
        }
    };
};

class boss_kiljaeden : public CreatureScript
{
public:
    boss_kiljaeden() : CreatureScript("boss_kiljaeden") { }

    struct boss_kiljaedenAI : public ScriptedAI
    {
        boss_kiljaedenAI(Creature* creature) : ScriptedAI(creature)
        {
            instance = creature->GetInstanceScript();
			me->SetReactState(REACT_PASSIVE);
        }

        InstanceScript* instance;
		EventMap events;
		EventMap events2;
		uint8 phase;

        void InitializeAI()
        {
			ScriptedAI::InitializeAI();
			me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);

			phase = PHASE_NORMAL;
			events.Reset();
			events2.Reset();
			events2.ScheduleEvent(EVENT_INIT_FIGHT, 11000);
			events2.ScheduleEvent(EVENT_REBIRTH, 0);
			me->SetVisible(false);
        }

        void Reset()
        {
			events.Reset();
        }

		void EnterEvadeMode()
		{
			if (me->GetReactState() == REACT_PASSIVE)
				return;
			ScriptedAI::EnterEvadeMode();
		}

		void AttackStart(Unit* who)
		{
			if (me->GetReactState() == REACT_PASSIVE)
				return;
			ScriptedAI::AttackStart(who);
		}

		void DamageTaken(Unit*, uint32& damage, DamageEffectType, SpellSchoolMask)
		{
			if (damage >= me->GetHealth())
			{
				me->SetTarget(0);
				me->SetReactState(REACT_PASSIVE);
				me->RemoveAllAuras();
				me->DeleteThreatList();
				me->SetRegeneratingHealth(false);
				me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE);
				me->HandleEmoteCommand(EMOTE_ONESHOT_DROWN);
				me->resetAttackTimer();
				events.Reset();
				events2.Reset();
				events2.ScheduleEvent(EVENT_KILL_SELF, 500);
				damage = 0;
			}
		}

        void JustDied(Unit* /*killer*/)
        {
			Talk(SAY_KJ_DEATH);
            instance->SetBossState(DATA_KILJAEDEN, DONE);
			if (Creature* controller = ObjectAccessor::GetCreature(*me, instance->GetData64(NPC_KILJAEDEN_CONTROLLER)))
				Unit::Kill(controller, controller);
        }

		void DoAction(int32 param)
		{
			if (param == ACTION_NO_KILL_TALK)
			{
				events.ScheduleEvent(EVENT_NO_KILL_TALK, 0);
				Talk(SAY_KJ_DARKNESS);
			}
		}

        void KilledUnit(Unit* victim)
        {
			if (victim->GetTypeId() == TYPEID_PLAYER && events.GetNextEventTime(EVENT_NO_KILL_TALK) == 0)
				Talk(SAY_KJ_SLAY);
        }

        void EnterCombat(Unit* /*who*/)
        {
			events2.ScheduleEvent(EVENT_TEXT_SPEACH11, 26000, EVENT_GROUP_SPEACH);
			Talk(SAY_KJ_EMERGE);

			events.SetTimer(200000);
			events.ScheduleEvent(EVENT_CHECK_HEALTH85, 1000);
			events.ScheduleEvent(EVENT_CHECK_HEALTH55, 1000);
			events.ScheduleEvent(EVENT_CHECK_HEALTH25, 1000);
			events.ScheduleEvent(EVENT_SPELL_SOUL_FLAY, 0);
			events.ScheduleEvent(EVENT_SPELL_LEGION_LIGHTNING, 7000);
			events.ScheduleEvent(EVENT_SPELL_FIRE_BLOOM, 9000);
			events.ScheduleEvent(EVENT_SUMMON_ORBS, 10000);
        }

		void JustSummoned(Creature* summon)
		{
			if (summon->GetEntry() == NPC_ARMAGEDDON_TARGET)
			{
				summon->SetDisableGravity(true);
				summon->SetCanFly(true);
				summon->CastSpell(summon, SPELL_ARMAGEDDON_VISUAL, true);
				summon->SetPosition(summon->GetPositionX(), summon->GetPositionY(), summon->GetPositionZ()+20.0f, 0.0f);
				summon->m_Events.AddEvent(new CastArmageddon(summon), summon->m_Events.CalculateTime(6000));
				summon->DespawnOrUnsummon(10000);
			}
		}

        void UpdateAI(uint32 diff)
        {
			events2.Update(diff);
			switch (events2.ExecuteEvent())
			{
				case EVENT_KILL_SELF:
					Unit::Kill(me, me);
					break;
				case EVENT_REBIRTH:
					me->SetVisible(true);
					me->CastSpell(me, SPELL_REBIRTH, false);
					break;
				case EVENT_EMPOWER_ORBS1:
					if (Creature* kalec = ObjectAccessor::GetCreature(*me, instance->GetData64(NPC_KALECGOS_KJ)))
                        kalec->AI()->Talk(SAY_KALECGOS_READY1);
					EmpowerOrb(false);
					break;
				case EVENT_EMPOWER_ORBS2:
					if (Creature* kalec = ObjectAccessor::GetCreature(*me, instance->GetData64(NPC_KALECGOS_KJ)))
                        kalec->AI()->Talk(SAY_KALECGOS_READY2);
					EmpowerOrb(false);
					break;
				case EVENT_EMPOWER_ORBS3:
					if (Creature* kalec = ObjectAccessor::GetCreature(*me, instance->GetData64(NPC_KALECGOS_KJ)))
                        kalec->AI()->Talk(SAY_KALECGOS_READY_ALL);
					EmpowerOrb(true);
					break;
				case EVENT_INIT_FIGHT:
					me->SetReactState(REACT_AGGRESSIVE);
					me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
					me->SetInCombatWithZone();
					return;
				case EVENT_TEXT_SPEACH11:
					if (Creature* kalec = ObjectAccessor::GetCreature(*me, instance->GetData64(NPC_KALECGOS_KJ)))
						kalec->AI()->Talk(SAY_KALECGOS_JOIN);
					break;
				case EVENT_TEXT_SPEACH21:
					if (Creature* kalec = ObjectAccessor::GetCreature(*me, instance->GetData64(NPC_KALECGOS_KJ)))
						kalec->AI()->Talk(SAY_KALECGOS_AWAKEN);
					break;
				case EVENT_TEXT_SPEACH22:
					if (Creature* anveena = ObjectAccessor::GetCreature(*me, instance->GetData64(NPC_ANVEENA)))
						sCreatureTextMgr->SendChat(anveena, SAY_ANVEENA_IMPRISONED, NULL, CHAT_MSG_ADDON, LANG_ADDON, TEXT_RANGE_ZONE);
					break;
				case EVENT_TEXT_SPEACH23:
					Talk(SAY_KJ_PHASE3);
					break;
				case EVENT_TEXT_SPEACH31:
					if (Creature* kalec = ObjectAccessor::GetCreature(*me, instance->GetData64(NPC_KALECGOS_KJ)))
						kalec->AI()->Talk(SAY_KALECGOS_LETGO);
					break;
				case EVENT_TEXT_SPEACH32:
					if (Creature* anveena = ObjectAccessor::GetCreature(*me, instance->GetData64(NPC_ANVEENA)))
						sCreatureTextMgr->SendChat(anveena, SAY_ANVEENA_LOST, NULL, CHAT_MSG_ADDON, LANG_ADDON, TEXT_RANGE_ZONE);
					break;
				case EVENT_TEXT_SPEACH33:
					Talk(SAY_KJ_PHASE4);
					break;
				case EVENT_TEXT_SPEACH41:
					if (Creature* kalec = ObjectAccessor::GetCreature(*me, instance->GetData64(NPC_KALECGOS_KJ)))
						kalec->AI()->Talk(SAY_KALECGOS_FOCUS);
					break;
				case EVENT_TEXT_SPEACH42:
					if (Creature* anveena = ObjectAccessor::GetCreature(*me, instance->GetData64(NPC_ANVEENA)))
						sCreatureTextMgr->SendChat(anveena, SAY_ANVEENA_KALEC, NULL, CHAT_MSG_ADDON, LANG_ADDON, TEXT_RANGE_ZONE);
					break;
				case EVENT_TEXT_SPEACH43:
					if (Creature* kalec = ObjectAccessor::GetCreature(*me, instance->GetData64(NPC_KALECGOS_KJ)))
						kalec->AI()->Talk(SAY_KALECGOS_FATE);
					break;
				case EVENT_TEXT_SPEACH44:
					if (Creature* anveena = ObjectAccessor::GetCreature(*me, instance->GetData64(NPC_ANVEENA)))
						sCreatureTextMgr->SendChat(anveena, SAY_ANVEENA_GOODBYE, NULL, CHAT_MSG_ADDON, LANG_ADDON, TEXT_RANGE_ZONE);
					break;
				case EVENT_TEXT_SPEACH45:
					if (Creature* anveena = ObjectAccessor::GetCreature(*me, instance->GetData64(NPC_ANVEENA)))
					{
						anveena->RemoveAllAuras();
						anveena->DespawnOrUnsummon(3500);
					}
					break;
				case EVENT_TEXT_SPEACH46:
					if (Creature* anveena = ObjectAccessor::GetCreature(*me, instance->GetData64(NPC_ANVEENA)))
					{
						anveena->CastSpell(anveena, SPELL_SACRIFICE_OF_ANVEENA, true);
						me->CastSpell(me, SPELL_CUSTOM_08_STATE, true);
						me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PACIFIED);
						events.DelayEvents(7001);
						events2.ScheduleEvent(EVENT_RESTORE_MELEE, 7000);
					}
					Talk(SAY_KJ_PHASE5);
					break;
				case EVENT_RESTORE_MELEE:
					me->RemoveAurasDueToSpell(SPELL_CUSTOM_08_STATE);
					me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PACIFIED);
					break;
			}

			if (me->GetReactState() != REACT_AGGRESSIVE)
				return;

            if (!UpdateVictim())
                return;

			events.Update(diff);
			if (me->HasUnitState(UNIT_STATE_CASTING))
				return;
			
			switch (events.ExecuteEvent())
			{
				case EVENT_CHECK_HEALTH85:
					if (me->HealthBelowPct(85))
					{
						phase = PHASE_DARKNESS;
						events2.CancelEvent(EVENT_GROUP_SPEACH);
						events2.ScheduleEvent(EVENT_TEXT_SPEACH21, 16000, EVENT_GROUP_SPEACH);
						events2.ScheduleEvent(EVENT_TEXT_SPEACH22, 22000, EVENT_GROUP_SPEACH);
						events2.ScheduleEvent(EVENT_TEXT_SPEACH23, 28000, EVENT_GROUP_SPEACH);
						events2.RescheduleEvent(EVENT_EMPOWER_ORBS1, 35000);
						
						events.DelayEvents(2000);
						events.ScheduleEvent(EVENT_SPELL_SINISTER_REFLECTION, 500);
						events.ScheduleEvent(EVENT_SPELL_SHADOW_SPIKE, 1200);
						events.ScheduleEvent(EVENT_SPELL_FLAME_DART, 3000);
						events.RescheduleEvent(EVENT_SPELL_DARKNESS, 16000); // will be delayed by 29 secs
						break;
					}
					events.ScheduleEvent(EVENT_CHECK_HEALTH85, 0);
					break;
				
				case EVENT_CHECK_HEALTH55:
					if (me->HealthBelowPct(55))
					{
						phase = PHASE_ARMAGEDDON;
						events2.CancelEventGroup(EVENT_GROUP_SPEACH);
						events2.ScheduleEvent(EVENT_TEXT_SPEACH31, 16000, EVENT_GROUP_SPEACH);
						events2.ScheduleEvent(EVENT_TEXT_SPEACH32, 22000, EVENT_GROUP_SPEACH);
						events2.ScheduleEvent(EVENT_TEXT_SPEACH33, 28000, EVENT_GROUP_SPEACH);
						events2.RescheduleEvent(EVENT_EMPOWER_ORBS2, 35000);
						
						events.DelayEvents(2000);
						events.ScheduleEvent(EVENT_SPELL_SINISTER_REFLECTION, 500);
						events.ScheduleEvent(EVENT_SPELL_SHADOW_SPIKE, 1200);
						events.RescheduleEvent(EVENT_SPELL_DARKNESS, 15000); // will be delayed by 29 secs
						events.ScheduleEvent(EVENT_SPELL_ARMAGEDDON, 10000);
						break;
					}
					events.ScheduleEvent(EVENT_CHECK_HEALTH55, 0);
					break;
				
				case EVENT_CHECK_HEALTH25:
					if (me->HealthBelowPct(25))
					{
						phase = PHASE_SACRIFICE;
						events2.CancelEventGroup(EVENT_GROUP_SPEACH);
						events2.ScheduleEvent(EVENT_TEXT_SPEACH41, 8000, EVENT_GROUP_SPEACH);
						events2.ScheduleEvent(EVENT_TEXT_SPEACH42, 18000, EVENT_GROUP_SPEACH);
						events2.ScheduleEvent(EVENT_TEXT_SPEACH43, 20200, EVENT_GROUP_SPEACH);
						events2.ScheduleEvent(EVENT_TEXT_SPEACH44, 25000, EVENT_GROUP_SPEACH);
						events2.ScheduleEvent(EVENT_TEXT_SPEACH45, 28000, EVENT_GROUP_SPEACH);
						events2.ScheduleEvent(EVENT_TEXT_SPEACH46, 30000, EVENT_GROUP_SPEACH);
						events2.RescheduleEvent(EVENT_EMPOWER_ORBS3, 61000);

						events.CancelEvent(EVENT_SUMMON_ORBS);
						events.DelayEvents(4000);
						events.ScheduleEvent(EVENT_SPELL_SINISTER_REFLECTION, 500);
						events.ScheduleEvent(EVENT_SPELL_SHADOW_SPIKE, 1200);
						events.RescheduleEvent(EVENT_SPELL_DARKNESS, 15000); // will be delayed by 29 secs
						events.ScheduleEvent(EVENT_SPELL_ARMAGEDDON, 1500);
						break;
					}
					events.ScheduleEvent(EVENT_CHECK_HEALTH25, 0);
					break;
				case EVENT_SPELL_SOUL_FLAY:
					me->CastSpell(me->GetVictim(), SPELL_SOUL_FLAY, false);
					events.ScheduleEvent(EVENT_SPELL_SOUL_FLAY, urand(4000, 5000));
					break;
				case EVENT_SPELL_LEGION_LIGHTNING:
					if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 40.0f, true))
						me->CastSpell(target, SPELL_LEGION_LIGHTNING, false);
					events.ScheduleEvent(EVENT_SPELL_LEGION_LIGHTNING, phase == PHASE_SACRIFICE ? 15000 : 30000);
					events.RescheduleEvent(EVENT_SPELL_SOUL_FLAY, 2000);
                    break;
                case EVENT_SPELL_FIRE_BLOOM:
					me->CastCustomSpell(SPELL_FIRE_BLOOM, SPELLVALUE_MAX_TARGETS, 5, me, TRIGGERED_NONE);
					me->SetTarget(me->GetVictim()->GetGUID());
					events.ScheduleEvent(EVENT_SPELL_FIRE_BLOOM, phase == PHASE_SACRIFICE ? 20000 : 40000);
					events.RescheduleEvent(EVENT_SPELL_SOUL_FLAY, 1500);
                    break;
		        case EVENT_SUMMON_ORBS:
                    for (uint8 i = 1; i < phase; ++i)
                    {
						float x = me->GetPositionX() + 18.0f*cos((i*2.0f-1.0f)*M_PI/3.0f);
                        float y = me->GetPositionY() + 18.0f*sin((i*2.0f-1.0f)*M_PI/3.0f);
                        if (Creature* orb = me->SummonCreature(NPC_SHIELD_ORB, x, y, 40.0f, 0, TEMPSUMMON_CORPSE_DESPAWN))
						{
							Movement::PointsArray movementArray;
							movementArray.push_back(G3D::Vector3(x, y, 40.0f));

							// generate movement array
							for (uint8 j = 1; j < 20; ++j)
							{
								x = me->GetPositionX() + 18.0f*cos(((i*2.0f-1.0f)*M_PI/3.0f) + (j/20.0f*2*M_PI));
								y = me->GetPositionY() + 18.0f*sin(((i*2.0f-1.0f)*M_PI/3.0f) + (j/20.0f*2*M_PI));
								movementArray.push_back(G3D::Vector3(x, y, 40.0f));
							}
							
							Movement::MoveSplineInit init(orb);
							init.MovebyPath(movementArray);
							init.SetCyclic();
							init.Launch();
						}
                    }
					events.ScheduleEvent(EVENT_SUMMON_ORBS, 40000);
                    break;
				case EVENT_SPELL_SHADOW_SPIKE:
					events.DelayEvents(27000);
					me->CastSpell(me, SPELL_SHADOW_SPIKE, false);
                    break;
				case EVENT_SPELL_SINISTER_REFLECTION:
					Talk(SAY_KJ_REFLECTION);
					me->CastCustomSpell(SPELL_SINISTER_REFLECTION, SPELLVALUE_MAX_TARGETS, 1, me, TRIGGERED_NONE);
					me->CastCustomSpell(SPELL_SINISTER_REFLECTION, SPELLVALUE_MAX_TARGETS, 1, me, TRIGGERED_NONE);
					me->CastCustomSpell(SPELL_SINISTER_REFLECTION, SPELLVALUE_MAX_TARGETS, 1, me, TRIGGERED_NONE);
					me->CastCustomSpell(SPELL_SINISTER_REFLECTION, SPELLVALUE_MAX_TARGETS, 1, me, TRIGGERED_NONE);
					break;
				case EVENT_SPELL_FLAME_DART:
					me->CastSpell(me, SPELL_FLAME_DART, false);
					events.ScheduleEvent(EVENT_SPELL_FLAME_DART, 10000);
					break;
				case EVENT_SPELL_DARKNESS:
					Talk(EMOTE_KJ_DARKNESS);
					me->CastSpell(me, SPELL_DARKNESS_OF_A_THOUSAND_SOULS, false);
					events.ScheduleEvent(EVENT_SPELL_DARKNESS, phase == PHASE_SACRIFICE ? 20000 : 45000);
					events.DelayEvents(8000);
					break;
				case EVENT_SPELL_ARMAGEDDON:
					me->CastSpell(me, SPELL_ARMAGEDDON_PERIODIC, true);
					events.ScheduleEvent(EVENT_SPELL_ARMAGEDDON, phase == PHASE_SACRIFICE ? 20000 : 40000);
					break;

			}

            DoMeleeAttackIfReady();
        }

		void EmpowerOrb(bool empowerAll)
		{
			for (uint8 i = 0; i < 4; ++i)
			{
				if (GameObject* orb = ObjectAccessor::GetGameObject(*me, instance->GetData64(DATA_ORB_OF_THE_BLUE_DRAGONFLIGHT_1+i)))
				{
					if (orb->HasFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE))
					{
						orb->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE);
						if (Creature* trigger = me->SummonTrigger(orb->GetPositionX(), orb->GetPositionY(), orb->GetPositionZ(), 0, 10*MINUTE*IN_MILLISECONDS))
						{
							trigger->CastSpell(trigger, SPELL_RING_OF_BLUE_FLAMES, true, NULL, NULL, trigger->GetGUID());
							if (Creature* controller = ObjectAccessor::GetCreature(*me, instance->GetData64(NPC_KILJAEDEN_CONTROLLER)))
								controller->AI()->JustSummoned(trigger);
						}

						if (!empowerAll)
							break;
					}
				}
			}
		}
    };

    CreatureAI* GetAI(Creature* creature) const
    {
        return GetInstanceAI<boss_kiljaedenAI>(creature);
    }
};

enum postEvent
{
	SAY_VELEN_01						= 0,
	SAY_VELEN_02						= 1,
	SAY_VELEN_03						= 2,
	SAY_VELEN_04						= 3,
	SAY_VELEN_05						= 4,
	SAY_VELEN_06						= 5,
	SAY_VELEN_07						= 6,
	SAY_VELEN_08						= 7,
	SAY_VELEN_09						= 8,
	SAY_LIADRIN_01						= 0,
	SAY_LIADRIN_02						= 1,
	SAY_LIADRIN_03						= 2,

	NPC_SHATTERED_SUN_RIFTWAKER			= 26289,
	NPC_SHATTRATH_PORTAL_DUMMY			= 26251,
	NPC_INERT_PORTAL					= 26254,
	NPC_SHATTERED_SUN_SOLDIER			= 26259,
	NPC_LADY_LIADRIN					= 26247,
	NPC_PROPHET_VELEN					= 26246,
	NPC_THE_CORE_OF_ENTROPIUS			= 26262,

	SPELL_TELEPORT_AND_TRANSFORM		= 46473,
	SPELL_OPEN_PORTAL_FROM_SHATTRATH	= 46801,
	SPELL_TELEPORT_VISUAL				= 35517,
	SPELL_BOSS_ARCANE_PORTAL_STATE		= 42047,
	SPELL_CALL_ENTROPIUS				= 46818,
	SPELL_BLAZE_TO_LIGHT				= 46821,
	SPELL_SUNWELL_IGNITION				= 46822,

	EVENT_SCENE_01						= 1,
	EVENT_SCENE_02,
	EVENT_SCENE_03,
	EVENT_SCENE_04,
	EVENT_SCENE_05,
	EVENT_SCENE_06,
	EVENT_SCENE_07,
	EVENT_SCENE_08,
	EVENT_SCENE_09,
	EVENT_SCENE_10,
	EVENT_SCENE_11,
	EVENT_SCENE_12,
	EVENT_SCENE_13,
	EVENT_SCENE_14,
	EVENT_SCENE_15,
	EVENT_SCENE_16,
	EVENT_SCENE_17,
	EVENT_SCENE_18,
	EVENT_SCENE_19,
	EVENT_SCENE_20,
	EVENT_SCENE_21,
	EVENT_SCENE_22,
	EVENT_SCENE_23,
	EVENT_SCENE_24,
	EVENT_SCENE_25,
	EVENT_SCENE_26,
	EVENT_SCENE_27
};

class MoveDelayed : public BasicEvent
{
    public:
        MoveDelayed(Creature* owner, float x, float y, float z, float o) : _owner(owner), _x(x), _y(y), _z(z), _o(o)
        {
        }

        bool Execute(uint64 /*execTime*/, uint32 /*diff*/)
        {
			Movement::MoveSplineInit init(_owner);
			init.MoveTo(_x, _y, _z, false, true);
			init.SetFacing(_o);
			init.Launch();
            return true;
        }

    private:
        Creature* _owner;
		float _x, _y, _z, _o;
};

class FixOrientation : public BasicEvent
{
    public:
        FixOrientation(Creature* owner) : _owner(owner)
        {
        }

        bool Execute(uint64 /*execTime*/, uint32 /*diff*/)
        {
			std::list<Creature*> cList;
			_owner->GetCreaturesWithEntryInRange(cList, 20.0f, NPC_SHATTERED_SUN_SOLDIER);
			for (std::list<Creature*>::const_iterator itr = cList.begin(); itr != cList.end(); ++itr)
				(*itr)->SetFacingTo(_owner->GetOrientation());
            return true;
        }

    private:
        Creature* _owner;
};

class npc_kalecgos_kj : public CreatureScript
{
public:
    npc_kalecgos_kj() : CreatureScript("npc_kalecgos_kj") { }

    CreatureAI* GetAI(Creature* creature) const
    {
        return GetInstanceAI<npc_kalecgos_kjAI>(creature);
    }

    struct npc_kalecgos_kjAI : public NullCreatureAI
    {
        npc_kalecgos_kjAI(Creature* creature) : NullCreatureAI(creature), summons(me)
        {
            instance = creature->GetInstanceScript();
        }

		EventMap events;
        InstanceScript* instance;
        SummonList summons;

        void Reset()
        {
			events.Reset();
			summons.DespawnAll();
        }

		void DoAction(int32 param)
		{
			if (param == ACTION_START_POST_EVENT)
			{
				me->SetDisableGravity(false);
				me->SetCanFly(false);
				me->CastSpell(me, SPELL_TELEPORT_AND_TRANSFORM, true);
				events.ScheduleEvent(EVENT_SCENE_01, 35000);
			}
		}

        void JustSummoned(Creature* summon)
        {
            summons.Summon(summon);
			if (summon->GetEntry() == NPC_SHATTERED_SUN_RIFTWAKER)
			{
				summon->CastSpell(summon, SPELL_TELEPORT_VISUAL, true);
				Movement::MoveSplineInit init(summon);
				if (summons.size() == 1)
				{
					init.MoveTo(1727.08f, 656.82f, 28.37f, false, true);
					init.SetFacing(5.14f);
				}
				else
				{
					init.MoveTo(1738.84f, 627.32f, 28.26f, false, true);
					init.SetFacing(2.0f);
				}
				init.Launch();
			}
			else if (summon->GetEntry() == NPC_SHATTRATH_PORTAL_DUMMY)
			{
				if (Creature* riftwaker = summon->FindNearestCreature(NPC_SHATTERED_SUN_RIFTWAKER, 10.0f))
					riftwaker->CastSpell(summon, SPELL_OPEN_PORTAL_FROM_SHATTRATH, false);
				summon->SetWalk(true);
				summon->GetMotionMaster()->MovePoint(0, summon->GetPositionX(), summon->GetPositionY(), summon->GetPositionZ()+30.0f, false, true);
			}
			else if (summon->GetEntry() == NPC_INERT_PORTAL)
				summon->CastSpell(summon, SPELL_BOSS_ARCANE_PORTAL_STATE, true);
			else if (summon->GetEntry() == NPC_SHATTERED_SUN_SOLDIER)
				summon->CastSpell(summon, SPELL_TELEPORT_VISUAL, true);
			else if (summon->GetEntry() == NPC_LADY_LIADRIN)
			{
				summon->CastSpell(summon, SPELL_TELEPORT_VISUAL, true);
				summon->SetWalk(true);
			}
			else if (summon->GetEntry() == NPC_PROPHET_VELEN)
			{
				summon->CastSpell(summon, SPELL_TELEPORT_VISUAL, true);
				summon->SetWalk(true);
				summon->GetMotionMaster()->MovePoint(0, 1710.15f, 639.23f, 27.311f, false, true);
			}
			else if (summon->GetEntry() == NPC_THE_CORE_OF_ENTROPIUS)
				summon->GetMotionMaster()->MovePoint(0, summon->GetPositionX(), summon->GetPositionY(), 30.0f);
        }

        void UpdateAI(uint32 diff)
        {
			events.Update(diff);
			switch (uint32 eventId = events.ExecuteEvent())
			{
				case EVENT_SCENE_01:
					Talk(SAY_KALECGOS_GOODBYE);
					events.ScheduleEvent(eventId+1, 15000);
					break;
				case EVENT_SCENE_02:
					me->SummonCreature(NPC_SHATTERED_SUN_RIFTWAKER, 1688.42f, 641.82f, 27.60f, 0.67f);
					me->SummonCreature(NPC_SHATTERED_SUN_RIFTWAKER, 1712.58f, 616.29f, 27.78f, 0.76f);
					events.ScheduleEvent(eventId+1, 6000);
					break;
				case EVENT_SCENE_03:
					me->SummonCreature(NPC_SHATTRATH_PORTAL_DUMMY, 1727.08f+cos(5.14f), 656.82f+sin(5.14f), 28.37f+2.0f, 0.0f, TEMPSUMMON_TIMED_DESPAWN, 10000);
					me->SummonCreature(NPC_SHATTRATH_PORTAL_DUMMY, 1738.84f+cos(2.0f), 627.32f+sin(2.0f), 28.26f+2.0f, 0.0f, TEMPSUMMON_TIMED_DESPAWN, 10000);
					events.ScheduleEvent(eventId+1, 11000);
					break;
				case EVENT_SCENE_04:
					me->SummonCreature(NPC_INERT_PORTAL, 1734.96f, 642.43f, 28.06f, 3.49f);
					events.ScheduleEvent(eventId+1, 4000);
					break;
				case EVENT_SCENE_05:
					if (Creature* first = me->SummonCreature(NPC_SHATTERED_SUN_SOLDIER, 1729.48f, 640.49f, 28.06f, 3.49f))
					{
						first->m_Events.AddEvent(new MoveDelayed(first, 1718.70f, 607.78f, 28.06f, 2.323f), first->m_Events.CalculateTime(5000));
						first->m_Events.AddEvent(new FixOrientation(first), first->m_Events.CalculateTime(12000));
						for (uint8 i = 0; i < 9; ++i)
							if (Creature* follower = me->SummonCreature(NPC_SHATTERED_SUN_SOLDIER, 1729.48f+5*cos(i*2.0f*M_PI/9), 640.49f+5*sin(i*2.0f*M_PI/9), 28.06f, 3.49f))
								follower->GetMotionMaster()->MoveFollow(first, 3.0f, follower->GetAngle(first));
					}
					events.ScheduleEvent(eventId+1, 10000);
					break;
				case EVENT_SCENE_06:
					if (Creature* first = me->SummonCreature(NPC_SHATTERED_SUN_SOLDIER, 1729.48f, 640.49f, 28.06f, 3.49f))
					{
						first->m_Events.AddEvent(new MoveDelayed(first, 1678.69f, 649.27f, 28.06f, 5.46f), first->m_Events.CalculateTime(5000));
						first->m_Events.AddEvent(new FixOrientation(first), first->m_Events.CalculateTime(14500));
						for (uint8 i = 0; i < 9; ++i)
							if (Creature* follower = me->SummonCreature(NPC_SHATTERED_SUN_SOLDIER, 1729.48f+5*cos(i*2.0f*M_PI/9), 640.49f+5*sin(i*2.0f*M_PI/9), 28.06f, 3.49f))
								follower->GetMotionMaster()->MoveFollow(first, 3.0f, follower->GetAngle(first));
					}
					events.ScheduleEvent(eventId+1, 12000);
					break;
				case EVENT_SCENE_07:
					me->SummonCreature(NPC_LADY_LIADRIN, 1719.87f, 644.265f, 28.06f, 3.83f);
					me->SummonCreature(NPC_PROPHET_VELEN, 1717.97f, 646.44f, 28.06f, 3.94f);
					events.ScheduleEvent(eventId+1, 7000);
					break;
				case EVENT_SCENE_08:
					if (Creature* velen = summons.GetCreatureWithEntry(NPC_PROPHET_VELEN))
						velen->AI()->Talk(SAY_VELEN_01);
					events.ScheduleEvent(eventId+1, 25000);
					break;
				case EVENT_SCENE_09:
					if (Creature* velen = summons.GetCreatureWithEntry(NPC_PROPHET_VELEN))
						velen->AI()->Talk(SAY_VELEN_02);
					events.ScheduleEvent(eventId+1, 14500);
					break;
				case EVENT_SCENE_10:
					if (Creature* velen = summons.GetCreatureWithEntry(NPC_PROPHET_VELEN))
						velen->AI()->Talk(SAY_VELEN_03);
					events.ScheduleEvent(eventId+1, 12500);
					break;
				case EVENT_SCENE_11:
					me->SummonCreature(NPC_THE_CORE_OF_ENTROPIUS, 1698.86f, 628.73f, 92.83f, 0.0f);
					if (Creature* velen = summons.GetCreatureWithEntry(NPC_PROPHET_VELEN))
						velen->CastSpell(velen, SPELL_CALL_ENTROPIUS, false);
					events.ScheduleEvent(eventId+1, 8000);
					break;
				case EVENT_SCENE_12:
					if (Creature* velen = summons.GetCreatureWithEntry(NPC_PROPHET_VELEN))
					{
						velen->InterruptNonMeleeSpells(false);
						velen->AI()->Talk(SAY_VELEN_04);
					}
					events.ScheduleEvent(eventId+1, 20000);
					break;
				case EVENT_SCENE_13:
					if (Creature* liadrin = summons.GetCreatureWithEntry(NPC_LADY_LIADRIN))
						liadrin->GetMotionMaster()->MovePoint(0, 1711.28f, 637.29f, 27.29f);
					events.ScheduleEvent(eventId+1, 6000);
					break;
				case EVENT_SCENE_14:
					if (Creature* liadrin = summons.GetCreatureWithEntry(NPC_LADY_LIADRIN))
						liadrin->AI()->Talk(SAY_LIADRIN_01);
					events.ScheduleEvent(eventId+1, 10000);
					break;
				case EVENT_SCENE_15:
					if (Creature* velen = summons.GetCreatureWithEntry(NPC_PROPHET_VELEN))
						velen->AI()->Talk(SAY_VELEN_05);
					events.ScheduleEvent(eventId+1, 14000);
					break;
				case EVENT_SCENE_16:
					if (Creature* liadrin = summons.GetCreatureWithEntry(NPC_LADY_LIADRIN))
						liadrin->AI()->Talk(SAY_LIADRIN_02);
					events.ScheduleEvent(eventId+1, 2000);
					break;
				case EVENT_SCENE_17:
					if (Creature* velen = summons.GetCreatureWithEntry(NPC_PROPHET_VELEN))
						velen->AI()->Talk(SAY_VELEN_06);
					events.ScheduleEvent(eventId+1, 3000);
					break;
				case EVENT_SCENE_18:
					if (Creature* core = summons.GetCreatureWithEntry(NPC_THE_CORE_OF_ENTROPIUS))
					{
						core->RemoveAllAuras();
						core->CastSpell(core, SPELL_BLAZE_TO_LIGHT, true);
					}
					events.ScheduleEvent(eventId+1, 8000);
					break;
				case EVENT_SCENE_19:
					if (Creature* core = summons.GetCreatureWithEntry(NPC_THE_CORE_OF_ENTROPIUS))
					{
						core->SetObjectScale(0.75f);
						core->GetMotionMaster()->MovePoint(0, core->GetPositionX(), core->GetPositionY(), 28.0f);
					}
					events.ScheduleEvent(eventId+1, 2000);
					break;
				case EVENT_SCENE_20:
					if (Creature* core = summons.GetCreatureWithEntry(NPC_THE_CORE_OF_ENTROPIUS))
						core->CastSpell(core, SPELL_SUNWELL_IGNITION, true);
					events.ScheduleEvent(eventId+1, 3000);
					break;
				case EVENT_SCENE_21:
					if (Creature* velen = summons.GetCreatureWithEntry(NPC_PROPHET_VELEN))
						velen->AI()->Talk(SAY_VELEN_07);
					events.ScheduleEvent(eventId+1, 15000);
					break;
				case EVENT_SCENE_22:
					if (Creature* liadrin = summons.GetCreatureWithEntry(NPC_LADY_LIADRIN))
						liadrin->AI()->Talk(SAY_LIADRIN_03);
					events.ScheduleEvent(eventId+1, 20000);
					break;
				case EVENT_SCENE_23:
					if (Creature* velen = summons.GetCreatureWithEntry(NPC_PROPHET_VELEN))
						velen->AI()->Talk(SAY_VELEN_08);
					if (Creature* liadrin = summons.GetCreatureWithEntry(NPC_LADY_LIADRIN))
						liadrin->SetStandState(UNIT_STAND_STATE_KNEEL);
					events.ScheduleEvent(eventId+1, 8000);
					break;
				case EVENT_SCENE_24:
					if (Creature* velen = summons.GetCreatureWithEntry(NPC_PROPHET_VELEN))
						velen->AI()->Talk(SAY_VELEN_09);
					events.ScheduleEvent(eventId+1, 5000);
					break;
				case EVENT_SCENE_25:
					if (Creature* velen = summons.GetCreatureWithEntry(NPC_PROPHET_VELEN))
					{
						velen->GetMotionMaster()->MovePoint(0, 1739.38f, 643.79f, 28.06f);
						velen->DespawnOrUnsummon(5000);
					}
					events.ScheduleEvent(eventId+1, 3000);
					break;
				case EVENT_SCENE_26:
					for (SummonList::const_iterator itr = summons.begin(); itr != summons.end(); ++itr)
						if (Creature* summon = ObjectAccessor::GetCreature(*me, *itr))
							if (summon->GetEntry() == NPC_SHATTERED_SUN_SOLDIER)
							{
								summon->GetMotionMaster()->MovePoint(0, 1739.38f, 643.79f, 28.06f);
								summon->DespawnOrUnsummon(summon->GetExactDist2d(1734.96f, 642.43f)*100);
							}
					events.ScheduleEvent(eventId+1, 7000);
					break;
				case EVENT_SCENE_27:
					me->setActive(false);
					summons.DespawnEntry(NPC_INERT_PORTAL);
					summons.DespawnEntry(NPC_SHATTERED_SUN_RIFTWAKER);
					break;
			}
        }
    };
};

class spell_kiljaeden_shadow_spike : public SpellScriptLoader
{
    public:
        spell_kiljaeden_shadow_spike() : SpellScriptLoader("spell_kiljaeden_shadow_spike") { }

        class spell_kiljaeden_shadow_spike_AuraScript : public AuraScript
        {
            PrepareAuraScript(spell_kiljaeden_shadow_spike_AuraScript);

            void HandlePeriodic(AuraEffect const* aurEff)
            {
                PreventDefaultAction();
				if (Unit* target = GetUnitOwner()->GetAI()->SelectTarget(SELECT_TARGET_RANDOM, 0, 60.0f, true))
					GetUnitOwner()->CastSpell(target, GetSpellInfo()->Effects[aurEff->GetEffIndex()].TriggerSpell, true);
            }

            void Register()
            {
                OnEffectPeriodic += AuraEffectPeriodicFn(spell_kiljaeden_shadow_spike_AuraScript::HandlePeriodic, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL);
            }
        };

        AuraScript* GetAuraScript() const
        {
            return new spell_kiljaeden_shadow_spike_AuraScript();
        }
};

class spell_kiljaeden_sinister_reflection : public SpellScriptLoader
{
	public:
		spell_kiljaeden_sinister_reflection() : SpellScriptLoader("spell_kiljaeden_sinister_reflection") { }

		class spell_kiljaeden_sinister_reflection_SpellScript : public SpellScript
		{
			PrepareSpellScript(spell_kiljaeden_sinister_reflection_SpellScript);

			void FilterTargets(std::list<WorldObject*>& targets)
			{
				targets.remove_if(Trinity::UnitAuraCheck(true, SPELL_VENGEANCE_OF_THE_BLUE_FLIGHT));
			}

			void HandleScriptEffect(SpellEffIndex effIndex)
			{
				PreventHitDefaultEffect(effIndex);
				if (Unit* target = GetHitUnit())
				{
					target->CastSpell(target, SPELL_SINISTER_REFLECTION_SUMMON, true);
					//target->CastSpell(target, SPELL_SINISTER_REFLECTION_CLONE, true);
				}
			}

			void Register()
			{
				OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_kiljaeden_sinister_reflection_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY);
				OnEffectHitTarget += SpellEffectFn(spell_kiljaeden_sinister_reflection_SpellScript::HandleScriptEffect, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
			}
		};

		SpellScript* GetSpellScript() const
		{
			return new spell_kiljaeden_sinister_reflection_SpellScript();
		}
};

class spell_kiljaeden_sinister_reflection_clone : public SpellScriptLoader
{
	public:
		spell_kiljaeden_sinister_reflection_clone() : SpellScriptLoader("spell_kiljaeden_sinister_reflection_clone") { }

		class spell_kiljaeden_sinister_reflection_clone_SpellScript : public SpellScript
		{
			PrepareSpellScript(spell_kiljaeden_sinister_reflection_clone_SpellScript);

			void FilterTargets(std::list<WorldObject*>& targets)
			{
				targets.sort(Trinity::ObjectDistanceOrderPred(GetCaster()));
				WorldObject* target = targets.front();
				
				targets.clear();
				if (target && target->GetTypeId() == TYPEID_UNIT)
				{
					target->ToCreature()->AI()->SetData(1, GetCaster()->getClass());
					targets.push_back(target);
				}				
			}

			void Register()
			{
				OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_kiljaeden_sinister_reflection_clone_SpellScript::FilterTargets, EFFECT_ALL, TARGET_UNIT_SRC_AREA_ENEMY);
			}
		};

		SpellScript* GetSpellScript() const
		{
			return new spell_kiljaeden_sinister_reflection_clone_SpellScript();
		}
};

class spell_kiljaeden_flame_dart : public SpellScriptLoader
{
	public:
		spell_kiljaeden_flame_dart() : SpellScriptLoader("spell_kiljaeden_flame_dart") { }

		class spell_kiljaeden_flame_dart_SpellScript : public SpellScript
		{
			PrepareSpellScript(spell_kiljaeden_flame_dart_SpellScript);

			void HandleSchoolDamage(SpellEffIndex effIndex)
			{
				if (Unit* target = GetHitUnit())
					target->CastSpell(target, SPELL_FLAME_DART_EXPLOSION, true);
			}

			void Register()
			{
				OnEffectHitTarget += SpellEffectFn(spell_kiljaeden_flame_dart_SpellScript::HandleSchoolDamage, EFFECT_0, SPELL_EFFECT_SCHOOL_DAMAGE);
			}
		};

		SpellScript* GetSpellScript() const
		{
			return new spell_kiljaeden_flame_dart_SpellScript();
		}
};

class spell_kiljaeden_darkness : public SpellScriptLoader
{
    public:
        spell_kiljaeden_darkness() : SpellScriptLoader("spell_kiljaeden_darkness") { }

        class spell_kiljaeden_darkness_AuraScript : public AuraScript
        {
            PrepareAuraScript(spell_kiljaeden_darkness_AuraScript);

			void HandleRemove(AuraEffect const* aurEff, AuraEffectHandleModes /*mode*/)
            {
				if (GetUnitOwner()->GetTypeId() == TYPEID_UNIT)
					GetUnitOwner()->ToCreature()->AI()->DoAction(ACTION_NO_KILL_TALK);

				GetUnitOwner()->CastSpell(GetUnitOwner(), SPELL_DARKNESS_OF_A_THOUSAND_SOULS_DAMAGE, true);
            }

            void Register()
            {
                OnEffectRemove += AuraEffectRemoveFn(spell_kiljaeden_darkness_AuraScript::HandleRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL);
            }
        };

        AuraScript* GetAuraScript() const
        {
            return new spell_kiljaeden_darkness_AuraScript();
        }
};

class spell_kiljaeden_power_of_the_blue_flight : public SpellScriptLoader
{
	public:
		spell_kiljaeden_power_of_the_blue_flight() : SpellScriptLoader("spell_kiljaeden_power_of_the_blue_flight") { }

		class spell_kiljaeden_power_of_the_blue_flight_SpellScript : public SpellScript
		{
			PrepareSpellScript(spell_kiljaeden_power_of_the_blue_flight_SpellScript);

			void HandleScriptEffect(SpellEffIndex effIndex)
			{
				PreventHitDefaultEffect(effIndex);
				if (Player* player = GetHitPlayer())
				{
					player->CastSpell(player, SPELL_SUMMON_BLUE_DRAKE, true);
					player->CastSpell(player, SPELL_VENGEANCE_OF_THE_BLUE_FLIGHT, true);
				}
			}

			void Register()
			{
				OnEffectHitTarget += SpellEffectFn(spell_kiljaeden_power_of_the_blue_flight_SpellScript::HandleScriptEffect, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
			}
		};

		SpellScript* GetSpellScript() const
		{
			return new spell_kiljaeden_power_of_the_blue_flight_SpellScript();
		}
};

class spell_kiljaeden_vengeance_of_the_blue_flight : public SpellScriptLoader
{
    public:
        spell_kiljaeden_vengeance_of_the_blue_flight() : SpellScriptLoader("spell_kiljaeden_vengeance_of_the_blue_flight") { }

        class spell_kiljaeden_vengeance_of_the_blue_flight_AuraScript : public AuraScript
        {
            PrepareAuraScript(spell_kiljaeden_vengeance_of_the_blue_flight_AuraScript);

			void HandleApply(AuraEffect const* aurEff, AuraEffectHandleModes /*mode*/)
            {
				GetUnitOwner()->CastSpell(GetUnitOwner(), SPELL_POSSESS_DRAKE_IMMUNITY, true);
            }

			void HandleRemove(AuraEffect const* aurEff, AuraEffectHandleModes /*mode*/)
            {
				GetUnitOwner()->RemoveAurasDueToSpell(SPELL_POSSESS_DRAKE_IMMUNITY);
            }

            void Register()
            {
                OnEffectApply += AuraEffectApplyFn(spell_kiljaeden_vengeance_of_the_blue_flight_AuraScript::HandleApply, EFFECT_0, SPELL_AURA_MOD_POSSESS, AURA_EFFECT_HANDLE_REAL);
                OnEffectApply += AuraEffectApplyFn(spell_kiljaeden_vengeance_of_the_blue_flight_AuraScript::HandleApply, EFFECT_2, SPELL_AURA_MOD_PACIFY_SILENCE, AURA_EFFECT_HANDLE_REAL);
                OnEffectRemove += AuraEffectRemoveFn(spell_kiljaeden_vengeance_of_the_blue_flight_AuraScript::HandleRemove, EFFECT_0, SPELL_AURA_MOD_POSSESS, AURA_EFFECT_HANDLE_REAL);
                OnEffectRemove += AuraEffectRemoveFn(spell_kiljaeden_vengeance_of_the_blue_flight_AuraScript::HandleRemove, EFFECT_2, SPELL_AURA_MOD_PACIFY_SILENCE, AURA_EFFECT_HANDLE_REAL);
            }
        };

        AuraScript* GetAuraScript() const
        {
            return new spell_kiljaeden_vengeance_of_the_blue_flight_AuraScript();
        }
};

class spell_kiljaeden_armageddon_periodic : public SpellScriptLoader
{
    public:
        spell_kiljaeden_armageddon_periodic() : SpellScriptLoader("spell_kiljaeden_armageddon_periodic") { }

        class spell_kiljaeden_armageddon_periodic_AuraScript : public AuraScript
        {
            PrepareAuraScript(spell_kiljaeden_armageddon_periodic_AuraScript);

            void HandlePeriodic(AuraEffect const* aurEff)
            {
                PreventDefaultAction();
				if (Unit* target = GetUnitOwner()->GetAI()->SelectTarget(SELECT_TARGET_RANDOM, 0, 60.0f, true))
					GetUnitOwner()->CastSpell(target, GetSpellInfo()->Effects[aurEff->GetEffIndex()].TriggerSpell, true);
            }

            void Register()
            {
                OnEffectPeriodic += AuraEffectPeriodicFn(spell_kiljaeden_armageddon_periodic_AuraScript::HandlePeriodic, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL);
            }
        };

        AuraScript* GetAuraScript() const
        {
            return new spell_kiljaeden_armageddon_periodic_AuraScript();
        }
};

class spell_kiljaeden_armageddon_missile : public SpellScriptLoader
{
    public:
        spell_kiljaeden_armageddon_missile() : SpellScriptLoader("spell_kiljaeden_armageddon_missile") { }

        class spell_kiljaeden_armageddon_missile_SpellScript : public SpellScript
        {
            PrepareSpellScript(spell_kiljaeden_armageddon_missile_SpellScript);

            void SetDest(SpellDestination& dest)
            {
                Position const offset = { 0.0f, 0.0f, -20.0f, 0.0f };
                dest.RelocateOffset(offset);
            }

            void Register()
            {
                OnDestinationTargetSelect += SpellDestinationTargetSelectFn(spell_kiljaeden_armageddon_missile_SpellScript::SetDest, EFFECT_0, TARGET_DEST_CASTER);
            }
        };

        SpellScript* GetSpellScript() const
        {
            return new spell_kiljaeden_armageddon_missile_SpellScript();
        }
};

class spell_kiljaeden_dragon_breath : public SpellScriptLoader
{
	public:
		spell_kiljaeden_dragon_breath() : SpellScriptLoader("spell_kiljaeden_dragon_breath") { }

		class spell_kiljaeden_dragon_breath_SpellScript : public SpellScript
		{
			PrepareSpellScript(spell_kiljaeden_dragon_breath_SpellScript);

			void FilterTargets(std::list<WorldObject*>& targets)
			{
				targets.remove_if(Trinity::UnitAuraCheck(true, SPELL_VENGEANCE_OF_THE_BLUE_FLIGHT));
			}

			void Register()
			{
				OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_kiljaeden_dragon_breath_SpellScript::FilterTargets, EFFECT_ALL, TARGET_UNIT_CONE_ALLY);
			}
		};

		SpellScript* GetSpellScript() const
		{
			return new spell_kiljaeden_dragon_breath_SpellScript();
		}
};

void AddSC_boss_kiljaeden()
{
	new npc_kiljaeden_controller();
	new boss_kiljaeden();
	new npc_kalecgos_kj();
	new spell_kiljaeden_shadow_spike();
	new spell_kiljaeden_sinister_reflection();
	new spell_kiljaeden_sinister_reflection_clone();
	new spell_kiljaeden_flame_dart();
	new spell_kiljaeden_darkness();
	new spell_kiljaeden_power_of_the_blue_flight();
	new spell_kiljaeden_vengeance_of_the_blue_flight();
	new spell_kiljaeden_armageddon_periodic();
	new spell_kiljaeden_armageddon_missile();
	new spell_kiljaeden_dragon_breath();
}
